#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <Utilities/SpaceHash/space_hash_cuda.h>
#include <string>
using namespace PhysLeo;
namespace py = pybind11;

template<typename T>
static void declareSpaceHashCpu(py::module &mod, const std::string &typestr)
{
    using class_type = SpaceHashCpu<T>;
    auto pyclass_name = std::string("SpaceHashCpu") + typestr;
    py::class_<class_type, std::shared_ptr<class_type>>cls(mod, pyclass_name.c_str());

    cls.def(py::init());
    cls.def("setSpace", &class_type::setSpace);
    cls.def("constructHashTable", &class_type::constructHashTable);
    cls.def("queryNeighbor", &class_type::queryNeighbor);
    cls.def("bbox", &class_type::bbox);
}

template<typename T>
static void declareSpaceHashCuda(py::module &mod, const std::string &typestr)
{
    using class_type = SpaceHashCuda<T>;
    using base_type = SpaceHashCpu<T>;
    auto pyclass_name = std::string("SpaceHashCuda") + typestr;
    py::class_<class_type, base_type, std::shared_ptr<class_type>>cls(mod, pyclass_name.c_str());

    cls.def(py::init());
    cls.def("setSpace", &class_type::setSpace);
    cls.def("constructHashTable", &class_type::constructHashTable);
    cls.def("queryNeighbor", &class_type::queryNeighbor);
}

void initSpaceHash(py::module &mod)
{
    declareSpaceHashCpu<float>(mod, std::string("F"));
    declareSpaceHashCpu<double>(mod, std::string("D"));

    declareSpaceHashCuda<float>(mod, std::string("F"));
    declareSpaceHashCuda<double>(mod, std::string("D"));
}